package com.xuecheng.checkcode.domain.template.impl;

import cn.hutool.core.util.RandomUtil;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.xuecheng.checkcode.domain.model.dto.CheckCodeGenerateDto;
import com.xuecheng.checkcode.domain.template.AbstractCheckCodeTemplate;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @Author: LiJunXi
 * @Description:
 * @Date: 2024-09-08  08:32
 */
@Component("caffeineCheckCodeTemplate")
public class CaffeineCheckCodeTemplate extends AbstractCheckCodeTemplate {

    private static Cache<String, String> map = Caffeine.newBuilder()
            .maximumSize(10000)
            .expireAfterWrite(5, TimeUnit.MINUTES)
            .build();

    private static Cache<String, String> errorMap = Caffeine.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(1, TimeUnit.MINUTES)
            .build();

    private static Cache<String, String> banMap = Caffeine.newBuilder()
            .maximumSize(100)
            .expireAfterWrite(3, TimeUnit.MINUTES)
            .build();

    @Override
    public String getKey(String prefix) {
        String random = RandomUtil.randomString(7);
        return prefix + "caffeine:" + random + ":";
    }

    @Override
    public void save(CheckCodeGenerateDto checkCodeGenerateDto) {
        map.put(checkCodeGenerateDto.getKey(), checkCodeGenerateDto.getValue());
    }

    @Override
    public String getValue(String key) {
        return map.getIfPresent(key);
    }

    @Override
    public Boolean checkErrorTime(String key) {
        String errorKey = getErrorKey(key);
        String s = map.getIfPresent(errorKey);
        Integer count = 1;
        if (Objects.nonNull(s)){
            count = Integer.parseInt(s) + 1;
        }
        if (count >= 3){
            // 达到最大值
            banMap.put(getBanKey(key), "1");
            return true;
        }
        errorMap.put(errorKey, count.toString());

        return false;
    }

    @Override
    public void deleteKey(String key) {
        map.invalidate(key);
    }

    @Override
    public String getErrorKey(String key) {
        return key + "error:";
    }

    @Override
    public Boolean isBan(String key) {
        return Objects.nonNull(banMap.getIfPresent(getBanKey(key)));
    }

    @Override
    public String getBanKey(String key) {
        return key + "ban:";
    }
}
